﻿using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
using Loong.AspNetCore.Mvc.Extensions;
using Loong.Dependency;
using Loong.Domain.Uow;
using Loong.Reflection;

namespace Loong.AspNetCore.Mvc.Uow
{
    public class UowActionFilter : IAsyncActionFilter, ITransientDependency
    {
        private readonly AspNetCoreOptions _options;
        private readonly IUnitOfWorkManager _unitOfWorkManager;

        public UowActionFilter(
            IOptions<AspNetCoreOptions> options,
            IUnitOfWorkManager unitOfWorkManager)
        {
            _options = options.Value;
            _unitOfWorkManager = unitOfWorkManager;
        }

        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            if (!context.ActionDescriptor.IsControllerAction())
            {
                await next();
                return;
            }

            var unitOfWorkAttr =
                ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(
                    context.ActionDescriptor.GetMethodInfo(),
                    _options.DefaultUnitOfWorkAttribute
                );

            if (unitOfWorkAttr.IsDisabled)
            {
                await next();
                return;
            }

            using (var uow = _unitOfWorkManager.Begin(unitOfWorkAttr.CreateOptions()))
            {
                var result = await next();
                if (result.Exception == null || result.ExceptionHandled)
                {
                    await uow.CompleteAsync();
                }
            }
        }
    }
}
